package com.my.spring.auto;


import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Zijian Liao
 * @since 1.0.0
 */
public class AutoMain {

    private static Map<String, Object> map = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        // 放
        new AutoMain().doScan("com.my.spring.auto");
        // 使用
        new Boy((Car) map.get("car")).drive();

        /*Object bean = getBean(Car.class);
        new Boy((Car)bean).drive();*/
    }

    private static Object getBean(Class<?> clazz){
        // 先判断clazz是否为一个接口，是则判断map中是否存在子类
        if(clazz.isInterface()){
            for (Object value : map.values()) {
                if (clazz.isAssignableFrom(value.getClass())) {
                    return value;
                }
            }
            throw new RuntimeException("找不到bean");
        }
        return map.get(generateBeanName(clazz));
    }



    @SuppressWarnings(value = "all")
    private  void doScan(String basePackages) {
        // 获取资源信息
        URI resource = this.getResource(basePackages);

        File dir = new File(resource.getPath());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                // 递归扫描
                doScan(basePackages + "." + file.getName());
            }
            else {
                // com.my.spring.auto + . + Boy.class -> com.my.spring.auto.Boy
                String className = basePackages + "." + file.getName().replace(".class", "");
                // 实例化class
                this.instanceClass(className);
            }
        }
    }

    private final ClassLoader classLoader = AutoMain.class.getClassLoader();

    private void instanceClass(String className){
        try {
            // 加载类信息
            Class<?> clazz = classLoader.loadClass(className);
            // 判断是否标识Component注解
            if(clazz.isAnnotationPresent(Component.class)){
                // car: com.my.spring.auto.Car
                String beanName = generateBeanName(clazz);
                Object o = this.newInstance(clazz);
                map.put(beanName, o);
            }
        } catch (ClassNotFoundException ignore) {}
    }

    private URI getResource(String basePackages){
        // 将包格式替换为文件路径格式
        String packageSearchPath = basePackages.replace(".", "/");
        try {
            // 根据路径获取资源
            return classLoader.getResource(packageSearchPath).toURI();
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

    private static String generateBeanName(Class<?> clazz){
        return Introspector.decapitalize(clazz.getSimpleName());
    }

    private Object newInstance(Class<?> clazz){
        try {
            // 这里只支持默认构造器
            return clazz.getDeclaredConstructor().newInstance();
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
